package com.dmy.component;

import com.dmy.config.GlobleConfig;

import javax.swing.*;
import java.awt.*;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * 蛇的抽象
 */
public abstract class Snake {

    private JComponent jComponent;

    private static final int sd = GlobleConfig.S_SIZE; // 速度

    private String name; // 名称
    private int length; // 身体长度
    private int fx = -2; // 方向 1 上 ，-1 下 ，2 左 ， -2 右
    private boolean isLive = true; // 是否存活

    private Schain first; // 蛇头
    private Schain last; // 蛇尾

    private Timer t;

    public Snake() {
        InitConfig config = new InitConfig();
        init(config);
        initSnake(config);
        initMove();
    }

    public Snake(JComponent jComponent) {
        this();
        this.jComponent = jComponent;
    }

    private final void initSnake(InitConfig config) {

        this.name = config.getName();

        this.length = config.getSnakeLength();

        for (int i = 0; i < config.getSnakeLength(); i++) {
            Schain schain = null;
            if (i == 0) {
                schain = new Schain(config.getSnakeHeadColor(),new CoorNT(config.getX(),config.getY()), null, null);
                first = schain;
                last = schain;
            } else {
                generateSnakeBody();
            }
        }
    }

    // 生成蛇身 向右----》
    private void generateSnakeBody() {
        Schain l = this.last;
        Schain newSchain = new Schain(getRandomColor(), new CoorNT(l.coorNT.x - GlobleConfig.S_SIZE, l.coorNT.y), l,null);
        this.last = newSchain;
        l.next = this.last;
    }

    // 取随机颜色
    private final Color getRandomColor(){
        return  new Color(new Random().nextInt(255)+1,new Random().nextInt(255)+1,new Random().nextInt(255)+1);
    }

    // 钩子函数 初始化蛇
    protected void init(InitConfig config) { };

    /**
     * 绘制蛇
     * @param g
     */
    public final void paint(Graphics2D g){
        for (Schain c = first; c != null;c = c.next){
            if(c==first){
                g.setColor(Color.GREEN);
                g.setFont(new Font("",Font.ITALIC,9));
                g.drawString(this.getName(),this.first.coorNT.x,this.first.coorNT.y-26);
            }
            doPaint(g,c);
        }
    }

    private final void doPaint(Graphics2D g, Schain c) {
         g.setColor(c.getColor());
        CoorNT nt = c.getCoorNT();
        g.fillArc(nt.x,nt.y,GlobleConfig.S_SIZE,GlobleConfig.S_SIZE,0,360);
    }

    private final void upMove(){
        fx = 1;
        for (Schain c = last; c!=null;c = c.prev){
            if(c!=first){
                c.coorNT = c.prev.coorNT;
            }else{
                if(c.coorNT.y<=0){
                    c.coorNT.y= GlobleConfig.WINDOW_HEIGHT;
                }
                c.coorNT = new CoorNT(c.coorNT.x,c.coorNT.y-sd);
            }
        }
    }
    private final void downMove(){
        fx = -1;
        for (Schain c = last; c!=null;c = c.prev){
            if(c!=first){
                c.coorNT = c.prev.coorNT;
            }else{
                if(c.coorNT.y>=GlobleConfig.WINDOW_HEIGHT){
                    c.coorNT.y= 0;
                }
                c.coorNT = new CoorNT(c.coorNT.x,c.coorNT.y+sd);
            }
        }
    }
    private final void leftMove(){
        fx = 2;
        for (Schain c = last; c!=null;c = c.prev){
            if(c!=first){
                c.coorNT = c.prev.coorNT;
            }else{
                if(c.coorNT.x<=0){
                    c.coorNT.x= GlobleConfig.WINDOW_WIDTH;
                }
                c.coorNT = new CoorNT(c.coorNT.x-sd,c.coorNT.y);
            }
        }
    }
    private final void rightMove(){
        fx = -2;

        for (Schain c = last; c!=null;c = c.prev){
            if(c!=first){
                c.coorNT = c.prev.coorNT;
            }else{
                if(c.coorNT.x>=GlobleConfig.WINDOW_WIDTH){
                    c.coorNT.x= 0;
                }
                c.coorNT = new CoorNT(c.coorNT.x+sd,c.coorNT.y);
            }
        }
    }
    // 移动
    private final void initMove() {
        t=new Timer(200,(e) -> {
                switch (fx){
                    case 1:
                        upMove();
                        break;
                    case -1:
                        downMove();
                        break;
                    case 2:
                        leftMove();
                        break;
                    case -2:
                        rightMove();
                        break;
                }
                jComponent.repaint();
        });
        t.start();
    }

    // 蛇死亡 游戏结束
    public final void gameOver(int length) {
        System.out.println("你死了，结束，蛇身" + length);
    }

    public void moveUp() {
        this.fx= 1;
    }

    public void moveDown() {
        this.fx= -1;
    }
    public void moveLeft() {
        this.fx= 2;
    }
    public void moveRight() {
        this.fx= -2;
    }

    public void stopGame() {
        t.stop();
    }
    public void startGame() {
        t.start();
    }

    public void jianSD() {
        t.setDelay(t.getDelay()+20);
    }
    public void addSD() {
        t.setDelay(t.getDelay()>=40?t.getDelay()-20:20);
    }

    // 获取蛇头位置信息
    public Schain getSnakeHead() {

        return this.first;
    }

    public boolean addHead(Color color) {
        Schain l = last;
        Schain schain = new Schain(color, new CoorNT(l.coorNT.x, l.coorNT.y), l, null);
        last = schain;
        l.next = last;
        return true;
    }

    // 表示蛇身的 双向链表
    public final class Schain {
        private Color color; // 蛇身颜色
        private CoorNT coorNT; // 坐标

        private Schain prev; // 上一个指向
        private Schain next; // 下一个指向

        public Schain(Color color, CoorNT coorNT, Schain prev, Schain next) {
            this.color = color;
            this.coorNT = coorNT;
            this.prev = prev;
            this.next = next;
        }

        public Color getColor() {
            return color;
        }

        public void setColor(Color color) {
            this.color = color;
        }

        public CoorNT getCoorNT() {
            return coorNT;
        }

        public void setCoorNT(CoorNT coorNT) {
            this.coorNT = coorNT;
        }

        public Schain getPrev() {
            return prev;
        }

        public void setPrev(Schain prev) {
            this.prev = prev;
        }

        public Schain getNext() {
            return next;
        }

        public void setNext(Schain next) {
            this.next = next;
        }
    }

    // 坐标类
    public final class CoorNT {
        int x, y;

        public CoorNT(int x, int y) {
            this.x = x;
            this.y = y;
        }

        public int getX() {
            return x;
        }

        public void setX(int x) {
            this.x = x;
        }

        public int getY() {
            return y;
        }

        public void setY(int y) {
            this.y = y;
        }
    }

    // 初始化配置类
    protected final class InitConfig {
        private int snakeLength = 3; // 默认的蛇身长度
        private Color snakeHeadColor = Color.orange; // 默认的蛇头颜色
        private String name = "无名蛇"; // 默认蛇的名字
        private int x = 100;
        private int y = 100;

        public int getX() {
            return x;
        }

        public void setX(int x) {
            this.x = x;
        }

        public int getY() {
            return y;
        }

        public void setY(int y) {
            this.y = y;
        }

        public int getSnakeLength() {
            return snakeLength;
        }

        public void setSnakeLength(int snakeLength) {
            this.snakeLength = snakeLength < 2 ? 2 : snakeLength;
        }

        public Color getSnakeHeadColor() {
            return snakeHeadColor;
        }

        public void setSnakeHeadColor(Color snakeHeadColor) {
            this.snakeHeadColor = snakeHeadColor;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public final int getLength() {
        return length;
    }
}
